Exposing Limited Amounts of Tableau REST API Functionality to Users via tableau_tools

As of 2020.2, the Tableau Server REST API has two mechanisms for logging in: username/password or a Personal Access Token (PAT) . There is no direct way to directly start a REST API session using a SSO mechanism (SAML, JWT, etc.).  Even if you were able to, you might still want to restrict the user to only do certain actions (for example, enabling Querying methods but not Updates or Deletes).

The best practice for working around this is to wrap the Tableau REST API in another REST API service of your own design. Then within that wrapper, use a Server Administrator level account to log in to the Tableau Server REST API. In this article, we’ll discuss how to achieve this using tableau_tools, with both a simple and a more complex but efficient design pattern.

Prior to Tableau Server 2021.1, this pattern only worked with an Server Admin account that has logged in using Username/Password. PATs allow an admin to Impersonate into a regular user’s session starting in version 2021.1. This is our best practice recommendation for using the Tableau REST API out to a web application embedding Tableau Server views.

The Sign-In Method of the REST API allows a Server Administrator to sign-in AS any other user (similar to SQL Server User Impersonation). This creates an actual separate REST API session with its own distinct Token, as if the user had logged in themselves with their own username and password.

Using tableau_tools, you can easily implement this paradigm. At the most simple level, you could simply spawn off a new TableauServerRestNN() object for each user that comes in, using the same administrator. If you don’t have multiple sites, this can be pretty easily achieved:


user_rest_connections = {}
master_username = 'site_admin'
master_password = 'hackm3'
site_content_url = "mysite"
m = TableauServerRest32(server=server, username=master_username, password=master_password,
site_content_url=site_content_url)
m.signin()

user_to_impersonate_1 = 'user_a'
user_luid = m.query_user_luid(user_to_impersonate_1)
user_rest_connections[user_to_impersonate_1] = TableauServerRest32(server=server, username=master_username, password=master_password,
site_content_url=site_content_url)

user_rest_connections[user_to_impersonate_1].signin(user_luid)

user_to_impersonate_2 = 'user_b'
user_luid = m.query_user_luid(user_to_impersonate_2)
user_rest_connections[user_to_impersonate_2] = TableauServerRest32(server=server, username=master_username,
password=master_password,
site_content_url=site_content_url)
user_rest_connections[user_to_impersonate_2].signin(user_luid)

RestTokensManager Class

However, if you have multiple sites, you have a whole other level of complexity, because you need to an Admin login for each site, as well as individual tokens for each user/site combination. An individual’s REST API session can be long-lived, but if you don’t cache that session token, you’ll end up having to sign-in and sign-out for every single command you make for that user.

To help manage all of this, there is a RestTokensManager class available starting in tableau_tools 5.2.0 . You can see an example of this in action in a very simplified Django views.py context in the example: limited_rest_api_wrapping_tableau_rest_api.py .

RestTokensManager is designed to handle all of the necessary connections on any number of sites. Rather than create a new TableauRestApiConnectionNN or TableauServerRestNN object for each connection, it simply swaps the login tokens in and out of a single object.

The basic functionality is that there is a switch_user_and_site() or switch_to_site_master(tableauConnectionObject) method of RestTokensManager  which take in either of the two connection objects and then once that completes, you use the connection object with any methods you want. It’s an efficient way to reuse a single connection to handle all of the various requests that come in.

Implementing Similar Functionality Outside of tableau_tools

There are three aspects to a Tableau Server REST API call: the session token, the userId, and the siteId (in tableau_tools you’ll see _luid which is the long way to refer to these IDs). If you know these three aspects, you can run every command for a given user.

You need the userId and the siteId to create an impersonated session, which gives you back the token for that session. You can get these IDs as an Admin for that Site, using the Query Users and Query Sites methods.

Every REST API call other than SIGN IN and schedule methods requires the siteId in the URL, and the token in the HTTP headers. There are a few calls that actually require the userId to scope the call just to the user themselves (but mostly that would matter in an admin context).

To manage everything, you just need to keep those three attributes available once you have signed in for any given user through the Impersonate sign-in. If you get back that the session has time out, go back to the Admin user, and do an Impersonate sign-in once again, then update your store of the token (userId and siteId should never change on a given  site). Remember, you have to keep track of these ID fields for EVERY SITE, even if they are the same user. That’s why they are referred to as LUID (Locally Unique IDs) — the IDs are unique to each Site on the Tableau Server.

One comment

Leave a comment